<?php
namespace Pinenut\Service\UrlRule;

use Pinenut\Service\UrlRule;

/**
 * правило маршрутизации с использованием чпу.
 * Это декоратор для стандартного правила.
 * в конструктуро создаем стандартное правило, из правила переданного в параметре вытаскиваем модель и роут.
 */
class UrlRuleFromModels extends UrlRule {

	/**
	 * наш экшен.
	 * 
	 * @var string
	 */
	public $route;

	/**
	 * Массив где ключ это наш параметр, а значение класс и метод в котором искать значение параметра.
	 * 
	 * @var array
	 */
	public $models;

	/**
	 * наше стандартное правило.
	 * 
	 * @var CUrlRule
	 */
	protected $rule;

	public function __construct($rule) {
		
		// заполняем в конструкторе наши параметры.
		$this->rule = new Standart($rule);
		$this->models = $rule['models'];
		$this->route = $rule['action'];
	}

	public function createUrl($route, array $params, $abs = false) {
		$rule = $this->rule;
		// в случае если роут в конструкторе не подходит роуту в стандартном правиле возвращаем ложь
		if ($route !== $rule->route)
			return false;
			
			// для каждого сегмента подменяем параметр - идентификатор на имя
		foreach ($this->models as $key => $model) {
			
			// проверяем - установлен ли параметр
			if (! isset($params[$key]))
				return false;
				
				// берем класс и метод из конфигурационного файла
			$class = $model['modelClass'];
			$method = $model['byKeyMethod'];
			
			// проверяем есть ли такой класс, если есть проверяем есть ли метод и только потом его выполняем
			if (class_exists($class)) {
				
				if (method_exists($class, $method)) {
					$params[$key] = $class::$method($params[$key]);
				} else
					throw new \Exception(
						'Статический метод ' . $method . ' модели ' . $class .
							 ' не найден', 500);
			} else
				throw new \Exception('Класс модели ' . $class . ' не найден', 
					500);
		}
		
		// вызываем креат стандартного рула.
		$url = $rule->createUrl($route, $params, $abs);
		
		return $url;
	}
	
	// парсим урл
	public function parseUrl($url = null, $method = null, $host = null, $params = null) {
		$rule = $this->rule;
		$request = $rule->parseUrl($url, $method, $host, $params);
		
		// в случае если нам не удалось распарсить стандартным, просто вертаем фолс.
		if (! $request)
			return false;
			
		$allParams = $params;
		// получаем параметры из реквеста.
		$params = $request->params();
		
		// для каждого сегмента подменяем параметр - идентификатор на имя
		foreach ($this->models as $key => $model) {
			
			// проверяем - установлен ли параметр
			if (! isset($params[$key])) {
				return false;
			}
			
			// берем класс и метод из конфигурационного файла
			$class = $model['modelClass'];
			$method = $model['byValueMethod'];
			
			// проверяем есть ли такой класс, если есть проверяем есть ли метод и только потом его выполняем
			if (class_exists($class)) {
				
				if (method_exists($class, $method)) {
					
					$value = $class::$method($params[$key]);
					
					// если нашли в классе и методе то что нам надо, тогда подменяем в массиве параметр, иначе просто ретюрнем фолс.
					if ($value !== null) {
						$params[$key] = $value;
						if (empty($params[$key])) {
							if (!isset($allParams[$key])) {
								unset($params[$key]);
							} else {
								$params[$key] = $allParams[$key];
							}
						}
					} else {
						return false;
					}
				} else
					throw new \Exception(
						'Статический метод ' . $method . ' модели ' . $class .
							 ' не найден', 500);
			} else
				throw new \Exception('Класс модели ' . $class . ' не найден', 
					500);
		}
		
		// тут заменяем параметры в реквесте на наши, которые мы заполнили в цикле
		$request->params($params);
		
		return $request;
	}
}
